From f8fb0a022853ab3f423889d442c695511ece3692 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 8 Jun 2017 15:09:04 -0700 Subject: [PATCH] Migrate from the `term` crate to `termcolor` The API of `termcolor` fits what the system gives us much more nicely and should be well battle-tested from ripgrep. Additionally we don't really need huge terminfo parsers, that wasn't every really the intention of the color support here. --- Cargo.lock | 22 +- Cargo.toml | 2 +- src/bin/cargo.rs | 4 +- src/bin/read_manifest.rs | 2 +- src/cargo/core/mod.rs | 2 +- src/cargo/core/shell.rs | 324 +++++++------------------ src/cargo/lib.rs | 87 ++----- src/cargo/ops/cargo_install.rs | 6 +- src/cargo/ops/cargo_new.rs | 12 +- src/cargo/ops/cargo_rustc/job_queue.rs | 9 +- src/cargo/ops/cargo_rustc/mod.rs | 9 +- src/cargo/ops/registry.rs | 24 +- src/cargo/util/config.rs | 14 +- src/cargo/util/errors.rs | 3 - src/cargo/util/flock.rs | 4 +- tests/cargotest/Cargo.toml | 1 - tests/cargotest/lib.rs | 1 - tests/new.rs | 2 +- tests/search.rs | 8 +- tests/shell.rs | 106 -------- 20 files changed, 165 insertions(+), 477 deletions(-) delete mode 100644 tests/shell.rs diff --git a/Cargo.lock b/Cargo.lock index eb2efec09..01942aad0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,7 +37,7 @@ dependencies = [ "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -119,7 +119,6 @@ dependencies = [ "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -740,12 +739,11 @@ dependencies = [ ] [[package]] -name = "term" -version = "0.4.5" +name = "termcolor" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "wincolor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -866,6 +864,15 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wincolor" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -956,7 +963,7 @@ dependencies = [ "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989" +"checksum termcolor 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5193a56b8d82014662c4b933dea6bec851daf018a2b01722e007daaf5f9dca" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread-id 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8df7875b676fddfadffd96deea3b1124e5ede707d4884248931077518cf1f773" "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" @@ -974,4 +981,5 @@ dependencies = [ "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum wincolor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99c2af1426e2166e6f66d88b09b2a4d63afce06875f149174e386f2f1ee9779b" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/Cargo.toml b/Cargo.toml index 26401fbd4..d5b4b4254 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ serde_json = "1.0" shell-escape = "0.1" tar = { version = "0.4", default-features = false } tempdir = "0.3" -term = "0.4.4" +termcolor = "0.3" toml = "0.4" url = "1.1" diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs index ae4409723..5e54973bf 100644 --- a/src/bin/cargo.rs +++ b/src/bin/cargo.rs @@ -15,7 +15,7 @@ use std::env; use std::fs; use std::path::{Path, PathBuf}; -use cargo::core::shell::{Verbosity, ColorConfig}; +use cargo::core::shell::{Shell, Verbosity}; use cargo::util::{self, CliResult, lev_distance, Config, CargoResult, CargoError, CargoErrorKind}; use cargo::util::CliError; @@ -75,7 +75,7 @@ fn main() { let config = match Config::default() { Ok(cfg) => cfg, Err(e) => { - let mut shell = cargo::shell(Verbosity::Verbose, ColorConfig::Auto); + let mut shell = Shell::new(); cargo::exit_with_error(e.into(), &mut shell) } }; diff --git a/src/bin/read_manifest.rs b/src/bin/read_manifest.rs index c97456757..651174e87 100644 --- a/src/bin/read_manifest.rs +++ b/src/bin/read_manifest.rs @@ -29,7 +29,7 @@ Options: pub fn execute(options: Options, config: &Config) -> CliResult { debug!("executing; cmd=cargo-read-manifest; args={:?}", env::args().collect::>()); - config.shell().set_color_config(options.flag_color.as_ref().map(|s| &s[..]))?; + config.shell().set_color_choice(options.flag_color.as_ref().map(|s| &s[..]))?; let root = find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())?; diff --git a/src/cargo/core/mod.rs b/src/cargo/core/mod.rs index 2c966f681..c63e9f8d3 100644 --- a/src/cargo/core/mod.rs +++ b/src/cargo/core/mod.rs @@ -6,7 +6,7 @@ pub use self::package_id::PackageId; pub use self::package_id_spec::PackageIdSpec; pub use self::registry::Registry; pub use self::resolver::Resolve; -pub use self::shell::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig}; +pub use self::shell::{Shell, Verbosity}; pub use self::source::{Source, SourceId, SourceMap, GitReference}; pub use self::summary::Summary; pub use self::workspace::{Workspace, WorkspaceConfig}; diff --git a/src/cargo/core/shell.rs b/src/cargo/core/shell.rs index 7ec566ac7..02161ff24 100644 --- a/src/cargo/core/shell.rs +++ b/src/cargo/core/shell.rs @@ -1,13 +1,8 @@ use std::fmt; use std::io::prelude::*; -use std::io; -use term::color::{Color, BLACK, RED, GREEN, YELLOW}; -use term::{self, Terminal, TerminfoTerminal, color, Attr}; - -use self::AdequateTerminal::{NoColor, Colored}; -use self::Verbosity::{Verbose, Quiet}; -use self::ColorConfig::{Auto, Always, Never}; +use termcolor::{self, StandardStream, Color, ColorSpec, WriteColor}; +use termcolor::Color::{Green, Red, Yellow}; use util::errors::CargoResult; @@ -18,120 +13,97 @@ pub enum Verbosity { Quiet } -#[derive(Clone, Copy, PartialEq)] -pub enum ColorConfig { - Auto, - Always, - Never -} - -impl fmt::Display for ColorConfig { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ColorConfig::Auto => "auto", - ColorConfig::Always => "always", - ColorConfig::Never => "never", - }.fmt(f) - } -} - -#[derive(Clone, Copy)] -pub struct ShellConfig { - pub color_config: ColorConfig, - pub tty: bool -} - -enum AdequateTerminal { - NoColor(Box), - Colored(Box> + Send>) -} - pub struct Shell { - terminal: AdequateTerminal, - config: ShellConfig, + err: StandardStream, + verbosity: Verbosity, + choice: ColorChoice, } -pub struct MultiShell { - out: Shell, - err: Shell, - verbosity: Verbosity +#[derive(PartialEq, Clone, Copy)] +pub enum ColorChoice { + Always, + Never, + CargoAuto, } -impl MultiShell { - pub fn new(out: Shell, err: Shell, verbosity: Verbosity) -> MultiShell { - MultiShell { out: out, err: err, verbosity: verbosity } - } - - // Create a quiet, basic shell from supplied writers. - pub fn from_write(out: Box, err: Box) -> MultiShell { - let config = ShellConfig { color_config: ColorConfig::Never, tty: false }; - let out = Shell { terminal: NoColor(out), config: config.clone() }; - let err = Shell { terminal: NoColor(err), config: config }; - MultiShell { - out: out, - err: err, - verbosity: Verbosity::Quiet, +impl Shell { + pub fn new() -> Shell { + Shell { + err: StandardStream::stderr(ColorChoice::CargoAuto.to_termcolor_color_choice()), + verbosity: Verbosity::Verbose, + choice: ColorChoice::CargoAuto, } } - pub fn out(&mut self) -> &mut Shell { - &mut self.out + fn print(&mut self, + status: &fmt::Display, + message: &fmt::Display, + color: Color, + justified: bool) -> CargoResult<()> { + match self.verbosity { + Verbosity::Quiet => Ok(()), + _ => { + self.err.reset()?; + self.err.set_color(ColorSpec::new() + .set_bold(true) + .set_fg(Some(color)))?; + if justified { + write!(self.err, "{:>12}", status)?; + } else { + write!(self.err, "{}", status)?; + } + self.err.reset()?; + write!(self.err, " {}\n", message)?; + Ok(()) + } + } } - pub fn err(&mut self) -> &mut Shell { + pub fn err(&mut self) -> &mut StandardStream { &mut self.err } - pub fn say(&mut self, message: T, color: Color) - -> CargoResult<()> { - match self.verbosity { - Quiet => Ok(()), - _ => self.out().say(message, color) - } - } - - pub fn status_with_color(&mut self, status: T, message: U, color: Color) - -> CargoResult<()> + pub fn status(&mut self, status: T, message: U) -> CargoResult<()> where T: fmt::Display, U: fmt::Display { - match self.verbosity { - Quiet => Ok(()), - _ => self.err().say_status(status, message, color, true) - } + self.print(&status, &message, Green, true) } - pub fn status(&mut self, status: T, message: U) -> CargoResult<()> + pub fn status_with_color(&mut self, + status: T, + message: U, + color: Color) -> CargoResult<()> where T: fmt::Display, U: fmt::Display { - self.status_with_color(status, message, GREEN) + self.print(&status, &message, color, true) } pub fn verbose(&mut self, mut callback: F) -> CargoResult<()> - where F: FnMut(&mut MultiShell) -> CargoResult<()> + where F: FnMut(&mut Shell) -> CargoResult<()> { match self.verbosity { - Verbose => callback(self), + Verbosity::Verbose => callback(self), _ => Ok(()) } } pub fn concise(&mut self, mut callback: F) -> CargoResult<()> - where F: FnMut(&mut MultiShell) -> CargoResult<()> + where F: FnMut(&mut Shell) -> CargoResult<()> { match self.verbosity { - Verbose => Ok(()), + Verbosity::Verbose => Ok(()), _ => callback(self) } } pub fn error(&mut self, message: T) -> CargoResult<()> { - self.err().say_status("error:", message, RED, false) + self.print(&"error:", &message, Red, false) } pub fn warn(&mut self, message: T) -> CargoResult<()> { match self.verbosity { - Quiet => Ok(()), - _ => self.err().say_status("warning:", message, YELLOW, false), + Verbosity::Quiet => Ok(()), + _ => self.print(&"warning:", &message, Yellow, false), } } @@ -139,179 +111,57 @@ impl MultiShell { self.verbosity = verbosity; } - pub fn set_color_config(&mut self, color: Option<&str>) -> CargoResult<()> { + pub fn verbosity(&self) -> Verbosity { + self.verbosity + } + + pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> { let cfg = match color { - Some("auto") => Auto, - Some("always") => Always, - Some("never") => Never, + Some("always") => ColorChoice::Always, + Some("never") => ColorChoice::Never, - None => Auto, + Some("auto") | + None => ColorChoice::CargoAuto, Some(arg) => bail!("argument for --color must be auto, always, or \ never, but found `{}`", arg), }; - self.out.set_color_config(cfg); - self.err.set_color_config(cfg); - Ok(()) - } - - pub fn get_verbose(&self) -> Verbosity { - self.verbosity + self.choice = cfg; + self.err = StandardStream::stderr(cfg.to_termcolor_color_choice()); + return Ok(()); } - pub fn color_config(&self) -> ColorConfig { - assert!(self.out.config.color_config == self.err.config.color_config); - self.out.config.color_config + pub fn color_choice(&self) -> ColorChoice { + self.choice } } -impl Shell { - pub fn create Box>(mut out_fn: T, config: ShellConfig) -> Shell { - let term = match Shell::get_term(out_fn()) { - Ok(t) => t, - Err(_) => NoColor(out_fn()) +impl ColorChoice { + fn to_termcolor_color_choice(&self) -> termcolor::ColorChoice { + return match *self { + ColorChoice::Always => termcolor::ColorChoice::Always, + ColorChoice::Never => termcolor::ColorChoice::Never, + ColorChoice::CargoAuto if isatty() => termcolor::ColorChoice::Auto, + ColorChoice::CargoAuto => termcolor::ColorChoice::Never, }; - Shell { - terminal: term, - config: config, - } - } - - #[cfg(any(windows))] - fn get_term(out: Box) -> CargoResult { - // Check if the creation of a console will succeed - if ::term::WinConsole::new(vec![0u8; 0]).is_ok() { - let t = ::term::WinConsole::new(out)?; - if !t.supports_color() { - Ok(NoColor(Box::new(t))) - } else { - Ok(Colored(Box::new(t))) - } - } else { - // If we fail to get a windows console, we try to get a `TermInfo` one - Ok(Shell::get_terminfo_term(out)) - } - } - - #[cfg(any(unix))] - fn get_term(out: Box) -> CargoResult { - Ok(Shell::get_terminfo_term(out)) - } - - fn get_terminfo_term(out: Box) -> AdequateTerminal { - // Use `TermInfo::from_env()` and `TerminfoTerminal::supports_color()` - // to determine if creation of a TerminfoTerminal is possible regardless - // of the tty status. --color options are parsed after Shell creation so - // always try to create a terminal that supports color output. Fall back - // to a no-color terminal regardless of whether or not a tty is present - // and if color output is not possible. - match ::term::terminfo::TermInfo::from_env() { - Ok(ti) => { - let term = TerminfoTerminal::new_with_terminfo(out, ti); - if !term.supports_color() { - NoColor(term.into_inner()) - } else { - // Color output is possible. - Colored(Box::new(term)) - } - }, - Err(_) => NoColor(out), - } - } - - pub fn set_color_config(&mut self, color_config: ColorConfig) { - self.config.color_config = color_config; - } - - pub fn say(&mut self, message: T, color: Color) -> CargoResult<()> { - self.reset()?; - if color != BLACK { self.fg(color)?; } - write!(self, "{}\n", message.to_string())?; - self.reset()?; - self.flush()?; - Ok(()) - } - - pub fn say_status(&mut self, - status: T, - message: U, - color: Color, - justified: bool) - -> CargoResult<()> - where T: fmt::Display, U: fmt::Display - { - self.reset()?; - if color != BLACK { self.fg(color)?; } - if self.supports_attr(Attr::Bold) { self.attr(Attr::Bold)?; } - if justified { - write!(self, "{:>12}", status.to_string())?; - } else { - write!(self, "{}", status)?; - } - self.reset()?; - write!(self, " {}\n", message)?; - self.flush()?; - Ok(()) - } - - fn fg(&mut self, color: color::Color) -> CargoResult { - let colored = self.colored(); - - match self.terminal { - Colored(ref mut c) if colored => c.fg(color)?, - _ => return Ok(false), - } - Ok(true) - } - - fn attr(&mut self, attr: Attr) -> CargoResult { - let colored = self.colored(); - - match self.terminal { - Colored(ref mut c) if colored => c.attr(attr)?, - _ => return Ok(false) - } - Ok(true) - } - - fn supports_attr(&self, attr: Attr) -> bool { - let colored = self.colored(); - - match self.terminal { - Colored(ref c) if colored => c.supports_attr(attr), - _ => false - } - } - - fn reset(&mut self) -> term::Result<()> { - let colored = self.colored(); + #[cfg(unix)] + fn isatty() -> bool { + extern crate libc; - match self.terminal { - Colored(ref mut c) if colored => c.reset()?, - _ => () + unsafe { libc::isatty(libc::STDERR_FILENO) != 0 } } - Ok(()) - } - - fn colored(&self) -> bool { - self.config.tty && Auto == self.config.color_config - || Always == self.config.color_config - } -} -impl Write for Shell { - fn write(&mut self, buf: &[u8]) -> io::Result { - match self.terminal { - Colored(ref mut c) => c.write(buf), - NoColor(ref mut n) => n.write(buf) - } - } + #[cfg(windows)] + fn isatty() -> bool { + extern crate kernel32; + extern crate winapi; - fn flush(&mut self) -> io::Result<()> { - match self.terminal { - Colored(ref mut c) => c.flush(), - NoColor(ref mut n) => n.flush() + unsafe { + let handle = kernel32::GetStdHandle(winapi::STD_ERROR_HANDLE); + let mut out = 0; + kernel32::GetConsoleMode(handle, &mut out) != 0 + } } } } diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index 38ebe82ae..e2b39cc92 100755 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -28,11 +28,11 @@ extern crate serde_ignored; extern crate shell_escape; extern crate tar; extern crate tempdir; -extern crate term; +extern crate termcolor; extern crate toml; extern crate url; -use std::io; +use std::io::Write; use std::fmt; use std::error::Error; @@ -41,9 +41,8 @@ use serde::Deserialize; use serde::ser; use docopt::Docopt; -use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig}; -use core::shell::Verbosity::{Verbose}; -use term::color::{BLACK}; +use core::Shell; +use core::shell::Verbosity::Verbose; pub use util::{CargoError, CargoErrorKind, CargoResult, CliError, CliResult, Config}; @@ -130,90 +129,46 @@ pub fn print_json(obj: &T) { println!("{}", encoded); } -pub fn shell(verbosity: Verbosity, color_config: ColorConfig) -> MultiShell { - enum Output { - Stdout, - Stderr, - } - - let tty = isatty(Output::Stderr); - - let config = ShellConfig { color_config: color_config, tty: tty }; - let err = Shell::create(|| Box::new(io::stderr()), config); - - let tty = isatty(Output::Stdout); - - let config = ShellConfig { color_config: color_config, tty: tty }; - let out = Shell::create(|| Box::new(io::stdout()), config); - - return MultiShell::new(out, err, verbosity); - - #[cfg(unix)] - fn isatty(output: Output) -> bool { - let fd = match output { - Output::Stdout => libc::STDOUT_FILENO, - Output::Stderr => libc::STDERR_FILENO, - }; - - unsafe { libc::isatty(fd) != 0 } - } - #[cfg(windows)] - fn isatty(output: Output) -> bool { - extern crate kernel32; - extern crate winapi; - - let handle = match output { - Output::Stdout => winapi::winbase::STD_OUTPUT_HANDLE, - Output::Stderr => winapi::winbase::STD_ERROR_HANDLE, - }; - - unsafe { - let handle = kernel32::GetStdHandle(handle); - let mut out = 0; - kernel32::GetConsoleMode(handle, &mut out) != 0 - } - } -} - -pub fn exit_with_error(err: CliError, shell: &mut MultiShell) -> ! { +pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! { debug!("exit_with_error; err={:?}", err); let CliError { error, exit_code, unknown } = err; // exit_code == 0 is non-fatal error, e.g. docopt version info let fatal = exit_code != 0; - let hide = unknown && shell.get_verbose() != Verbose; + let hide = unknown && shell.verbosity() != Verbose; if let Some(error) = error { - let _ignored_result = if hide { - shell.error("An unknown error occurred") + if hide { + drop(shell.error("An unknown error occurred")) } else if fatal { - shell.error(&error) + drop(shell.error(&error)) } else { - shell.say(&error, BLACK) - }; + drop(writeln!(shell.err(), "{}", error)) + } if !handle_cause(error, shell) || hide { - let _ = shell.err().say("\nTo learn more, run the command again \ - with --verbose.".to_string(), BLACK); + drop(writeln!(shell.err(), "\nTo learn more, run the command again \ + with --verbose.")); } } std::process::exit(exit_code) } -pub fn handle_error(err: CargoError, shell: &mut MultiShell) { +pub fn handle_error(err: CargoError, shell: &mut Shell) { debug!("handle_error; err={:?}", &err); let _ignored_result = shell.error(&err); handle_cause(err, shell); } -fn handle_cause(cargo_err: E, shell: &mut MultiShell) -> bool - where E: ChainedError + 'static { - fn print(error: String, shell: &mut MultiShell) { - let _ = shell.err().say("\nCaused by:", BLACK); - let _ = shell.err().say(format!(" {}", error), BLACK); +fn handle_cause(cargo_err: E, shell: &mut Shell) -> bool + where E: ChainedError + 'static +{ + fn print(error: String, shell: &mut Shell) { + drop(writeln!(shell.err(), "\nCaused by:")); + drop(writeln!(shell.err(), " {}", error)); } //Error inspection in non-verbose mode requires inspecting the @@ -228,7 +183,7 @@ fn handle_cause(cargo_err: E, shell: &mut MultiShell) -> bool std::mem::transmute::<&Error, &Error>(r) } - let verbose = shell.get_verbose(); + let verbose = shell.verbosity(); if verbose == Verbose { //The first error has already been printed to the shell diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index ceb67c323..5421ebbce 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -460,12 +460,10 @@ pub fn install_list(dst: Option<&str>, config: &Config) -> CargoResult<()> { let dst = resolve_root(dst, config)?; let dst = metadata(config, &dst)?; let list = read_crate_list(dst.file())?; - let mut shell = config.shell(); - let out = shell.out(); for (k, v) in list.v1.iter() { - writeln!(out, "{}:", k)?; + println!("{}:", k); for bin in v { - writeln!(out, " {}", bin)?; + println!(" {}", bin); } } Ok(()) diff --git a/src/cargo/ops/cargo_new.rs b/src/cargo/ops/cargo_new.rs index ad049e494..3ac323905 100644 --- a/src/cargo/ops/cargo_new.rs +++ b/src/cargo/ops/cargo_new.rs @@ -1,7 +1,8 @@ +use std::collections::BTreeMap; use std::env; use std::fs; +use std::io::Write; use std::path::Path; -use std::collections::BTreeMap; use serde::{Deserialize, Deserializer}; use serde::de; @@ -9,8 +10,6 @@ use serde::de; use git2::Config as GitConfig; use git2::Repository as GitRepository; -use term::color::BLACK; - use core::Workspace; use ops::is_bad_artifact_name; use util::{GitRepo, HgRepo, PijulRepo, internal}; @@ -111,10 +110,9 @@ fn get_name<'a>(path: &'a Path, opts: &'a NewOptions, config: &Config) -> CargoR } else { let new_name = strip_rust_affixes(dir_name); if new_name != dir_name { - let message = format!( - "note: package will be named `{}`; use --name to override", - new_name); - config.shell().say(&message, BLACK)?; + writeln!(config.shell().err(), + "note: package will be named `{}`; use --name to override", + new_name)?; } Ok(new_name) } diff --git a/src/cargo/ops/cargo_rustc/job_queue.rs b/src/cargo/ops/cargo_rustc/job_queue.rs index fa008289d..aec3e3c85 100644 --- a/src/cargo/ops/cargo_rustc/job_queue.rs +++ b/src/cargo/ops/cargo_rustc/job_queue.rs @@ -7,7 +7,6 @@ use std::sync::mpsc::{channel, Sender, Receiver}; use crossbeam::{self, Scope}; use jobserver::{Acquired, HelperThread}; -use term::color::YELLOW; use core::{PackageId, Target, Profile}; use util::{Config, DependencyQueue, Fresh, Dirty, Freshness}; @@ -212,7 +211,7 @@ impl<'a> JobQueue<'a> { } Message::Stdout(out) => { if cx.config.extra_verbose() { - writeln!(cx.config.shell().out(), "{}", out)?; + println!("{}", out); } } Message::Stderr(err) => { @@ -236,9 +235,9 @@ impl<'a> JobQueue<'a> { if self.active > 0 { error = Some("build failed".into()); handle_error(e, &mut *cx.config.shell()); - cx.config.shell().say( - "Build failed, waiting for other \ - jobs to finish...", YELLOW)?; + cx.config.shell().warn( + "build failed, waiting for other \ + jobs to finish...")?; } else { error = Some(e); diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index e77740763..67bb834a2 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -10,7 +10,7 @@ use serde_json; use core::{Package, PackageId, PackageSet, Target, Resolve}; use core::{Profile, Profiles, Workspace}; -use core::shell::ColorConfig; +use core::shell::ColorChoice; use util::{self, ProcessBuilder, machine_message}; use util::{Config, internal, profile, join_paths, short_hash}; use util::errors::{CargoResult, CargoResultExt}; @@ -679,9 +679,10 @@ fn build_base_args(cx: &mut Context, cmd.arg(&root_path(cx, unit)); - let color_config = cx.config.shell().color_config(); - if color_config != ColorConfig::Auto { - cmd.arg("--color").arg(&color_config.to_string()); + match cx.config.shell().color_choice() { + ColorChoice::Always => { cmd.arg("--color").arg("always"); } + ColorChoice::Never => { cmd.arg("--color").arg("never"); } + ColorChoice::CargoAuto => {} } if cx.build_config.json_messages { diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index 78681a690..01a5e0710 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -1,12 +1,12 @@ use std::env; use std::fs::{self, File}; +use std::io::Write; use std::iter::repeat; use std::time::Duration; use curl::easy::{Easy, SslOpt}; use git2; use registry::{Registry, NewCrate, NewCrateDependency}; -use term::color::BLACK; use url::percent_encoding::{percent_encode, QUERY_ENCODE_SET}; @@ -424,25 +424,19 @@ pub fn search(query: &str, } None => name }; - config.shell().say(line, BLACK)?; + writeln!(config.shell().err(), "{}", line)?; } let search_max_limit = 100; if total_crates > limit as u32 && limit < search_max_limit { - config.shell().say( - format!("... and {} crates more (use --limit N to see more)", - total_crates - limit as u32), - BLACK) - ?; + writeln!(config.shell().err(), + "... and {} crates more (use --limit N to see more)", + total_crates - limit as u32)?; } else if total_crates > limit as u32 && limit >= search_max_limit { - config.shell().say( - format!( - "... and {} crates more (go to http://crates.io/search?q={} to see more)", - total_crates - limit as u32, - percent_encode(query.as_bytes(), QUERY_ENCODE_SET) - ), - BLACK) - ?; + writeln!(config.shell().err(), + "... and {} crates more (go to http://crates.io/search?q={} to see more)", + total_crates - limit as u32, + percent_encode(query.as_bytes(), QUERY_ENCODE_SET))?; } Ok(()) diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index 32976225b..5edeeef96 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -12,8 +12,8 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::{Once, ONCE_INIT}; -use core::MultiShell; -use core::shell::{Verbosity, ColorConfig}; +use core::Shell; +use core::shell::Verbosity; use jobserver; use serde::{Serialize, Serializer}; use toml; @@ -28,7 +28,7 @@ use self::ConfigValue as CV; pub struct Config { home_path: Filesystem, - shell: RefCell, + shell: RefCell, rustc: LazyCell, values: LazyCell>, cwd: PathBuf, @@ -41,7 +41,7 @@ pub struct Config { } impl Config { - pub fn new(shell: MultiShell, + pub fn new(shell: Shell, cwd: PathBuf, homedir: PathBuf) -> Config { static mut GLOBAL_JOBSERVER: *mut jobserver::Client = 0 as *mut _; @@ -77,7 +77,7 @@ impl Config { } pub fn default() -> CargoResult { - let shell = ::shell(Verbosity::Verbose, ColorConfig::Auto); + let shell = Shell::new(); let cwd = env::current_dir().chain_err(|| { "couldn't get the current directory of the process" })?; @@ -106,7 +106,7 @@ impl Config { self.home_path.join("registry").join("src") } - pub fn shell(&self) -> RefMut { + pub fn shell(&self) -> RefMut { self.shell.borrow_mut() } @@ -405,7 +405,7 @@ impl Config { }; self.shell().set_verbosity(verbosity); - self.shell().set_color_config(color.map(|s| &s[..]))?; + self.shell().set_color_choice(color.map(|s| &s[..]))?; self.extra_verbose.set(extra_verbose); self.frozen.set(frozen); self.locked.set(locked); diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index 11d6dfdc6..7b51c527d 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -12,7 +12,6 @@ use curl; use git2; use semver; use serde_json; -use term; use toml; use registry; @@ -32,7 +31,6 @@ error_chain! { SerdeJson(serde_json::Error); TomlSer(toml::ser::Error); TomlDe(toml::de::Error); - Term(term::Error); ParseInt(num::ParseIntError); ParseBool(str::ParseBoolError); Parse(string::ParseError); @@ -78,7 +76,6 @@ impl CargoError { &CargoErrorKind::Semver(_) | &CargoErrorKind::Io(_) | &CargoErrorKind::SerdeJson(_) | - &CargoErrorKind::Term(_) | &CargoErrorKind::ParseInt(_) | &CargoErrorKind::ParseBool(_) | &CargoErrorKind::Parse(_) | diff --git a/src/cargo/util/flock.rs b/src/cargo/util/flock.rs index 505a88a00..4cdcf5f90 100644 --- a/src/cargo/util/flock.rs +++ b/src/cargo/util/flock.rs @@ -3,7 +3,7 @@ use std::io::*; use std::io; use std::path::{Path, PathBuf, Display}; -use term::color::CYAN; +use termcolor::Color::Cyan; use fs2::{FileExt, lock_contended_error}; #[allow(unused_imports)] use libc; @@ -290,7 +290,7 @@ fn acquire(config: &Config, } } let msg = format!("waiting for file lock on {}", msg); - config.shell().status_with_color("Blocking", &msg, CYAN)?; + config.shell().status_with_color("Blocking", &msg, Cyan)?; return block().chain_err(|| { format!("failed to lock file: {}", path.display()) diff --git a/tests/cargotest/Cargo.toml b/tests/cargotest/Cargo.toml index f5b1cc8ca..dea882638 100644 --- a/tests/cargotest/Cargo.toml +++ b/tests/cargotest/Cargo.toml @@ -21,6 +21,5 @@ serde = "1.0" serde_json = "1.0" tar = { version = "0.4", default-features = false } tempdir = "0.3" -term = "0.4.4" url = "1.1" winapi = "0.2" diff --git a/tests/cargotest/lib.rs b/tests/cargotest/lib.rs index 919768c18..dcb098a8e 100644 --- a/tests/cargotest/lib.rs +++ b/tests/cargotest/lib.rs @@ -13,7 +13,6 @@ extern crate serde; extern crate serde_json; extern crate tar; extern crate tempdir; -extern crate term; extern crate url; #[cfg(windows)] extern crate kernel32; #[cfg(windows)] extern crate winapi; diff --git a/tests/new.rs b/tests/new.rs index 8ba315056..fa75d2da8 100644 --- a/tests/new.rs +++ b/tests/new.rs @@ -155,7 +155,7 @@ use --name to override crate name")); fn rust_prefix_stripped() { assert_that(cargo_process("new").arg("--lib").arg("rust-foo").env("USER", "foo"), execs().with_status(0) - .with_stdout("note: package will be named `foo`; use --name to override")); + .with_stderr_contains("note: package will be named `foo`; use --name to override")); let toml = paths::root().join("rust-foo/Cargo.toml"); let mut contents = String::new(); File::open(&toml).unwrap().read_to_string(&mut contents).unwrap(); diff --git a/tests/search.rs b/tests/search.rs index 4c55058ad..ff224fe95 100644 --- a/tests/search.rs +++ b/tests/search.rs @@ -84,9 +84,7 @@ fn simple() { assert_that(cargo_process("search").arg("postgres") .arg("--host").arg(registry().to_string()), execs().with_status(0) - .with_stderr("\ -[UPDATING] registry `[..]`") - .with_stdout("\ + .with_stderr_contains("\ hoare = \"0.1.1\" # Design by contract style assertions for Rust")); } @@ -136,9 +134,7 @@ fn multiple_query_params() { assert_that(cargo_process("search").arg("postgres").arg("sql") .arg("--host").arg(registry().to_string()), execs().with_status(0) - .with_stderr("\ -[UPDATING] registry `[..]`") - .with_stdout("\ + .with_stderr_contains("\ hoare = \"0.1.1\" # Design by contract style assertions for Rust")); } diff --git a/tests/shell.rs b/tests/shell.rs deleted file mode 100644 index 8dc0786fc..000000000 --- a/tests/shell.rs +++ /dev/null @@ -1,106 +0,0 @@ -extern crate cargo; -extern crate cargotest; -extern crate hamcrest; -extern crate term; - -use std::io::prelude::*; -use std::io; -use std::sync::{Arc, Mutex}; - -use cargo::core::shell::ColorConfig::{Auto,Always, Never}; -use cargo::core::shell::{Shell, ShellConfig}; -use cargo::util::CargoResult; -use cargotest::support::{Tap, execs, shell_writes}; -use hamcrest::{assert_that}; -use term::{Terminal, TerminfoTerminal, color}; - -struct Sink(Arc>>); - -impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[test] -fn non_tty() { - let config = ShellConfig { color_config: Auto, tty: false }; - let a = Arc::new(Mutex::new(Vec::new())); - - Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| { - shell.say("Hey Alex", color::RED).unwrap(); - }); - let buf = a.lock().unwrap().clone(); - assert_that(&buf[..], shell_writes("Hey Alex\n")); -} - -#[test] -fn color_explicitly_disabled() { - let term = TerminfoTerminal::new(Vec::new()); - if term.is_none() { return } - - let config = ShellConfig { color_config: Never, tty: true }; - let a = Arc::new(Mutex::new(Vec::new())); - - Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| { - shell.say("Hey Alex", color::RED).unwrap(); - }); - let buf = a.lock().unwrap().clone(); - assert_that(&buf[..], shell_writes("Hey Alex\n")); -} - -#[test] -fn colored_shell() { - let term = TerminfoTerminal::new(Vec::new()); - if term.is_none() { return } - - let config = ShellConfig { color_config: Auto, tty: true }; - let a = Arc::new(Mutex::new(Vec::new())); - - Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| { - shell.say("Hey Alex", color::RED).unwrap(); - }); - let buf = a.lock().unwrap().clone(); - let expected_output = if term.unwrap().supports_color() { - shell_writes(colored_output("Hey Alex\n", color::RED).unwrap()) - } else { - shell_writes("Hey Alex\n") - }; - assert_that(&buf[..], expected_output); -} - -#[test] -fn color_explicitly_enabled() { - let term = TerminfoTerminal::new(Vec::new()); - if term.is_none() { return } - if !term.unwrap().supports_color() { return } - - let config = ShellConfig { color_config: Always, tty: false }; - let a = Arc::new(Mutex::new(Vec::new())); - - Shell::create(|| Box::new(Sink(a.clone())), config).tap(|shell| { - shell.say("Hey Alex", color::RED).unwrap(); - }); - let buf = a.lock().unwrap().clone(); - assert_that(&buf[..], - shell_writes(colored_output("Hey Alex\n", - color::RED).unwrap())); -} - -#[test] -fn no_term() { - // Verify that shell creation is successful when $TERM does not exist. - assert_that(cargotest::cargo_process().env_remove("TERM"), - execs().with_stderr("")); -} - -fn colored_output(string: &str, color: color::Color) -> CargoResult { - let mut term = TerminfoTerminal::new(Vec::new()).unwrap(); - term.reset()?; - term.fg(color)?; - write!(&mut term, "{}", string)?; - term.reset()?; - term.flush()?; - Ok(String::from_utf8_lossy(term.get_ref()).to_string()) -} -- 2.30.2